package com.dlc.shop.api.controller;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import com.dlc.shop.bean.app.param.CheckRegisterSmsParam;
import com.dlc.shop.bean.app.param.SendSmsParam;
import com.dlc.shop.bean.app.param.UserPwdUpdateParam;
import com.dlc.shop.bean.app.param.UserRegisterParam;
import com.dlc.shop.bean.enums.SendType;
import com.dlc.shop.bean.model.User;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.common.util.PasswordUtil;
import com.dlc.shop.common.util.PrincipalUtil;
import com.dlc.shop.common.util.RedisUtil;
import com.dlc.shop.live.common.service.LiveRoomService;
import com.dlc.shop.security.common.bo.UidInfoBO;
import com.dlc.shop.security.common.manager.PasswordManager;
import com.dlc.shop.security.common.manager.TokenStore;
import com.dlc.shop.security.common.service.AppConnectService;
import com.dlc.shop.security.common.util.AuthUserContext;
import com.dlc.shop.security.common.vo.TokenInfoVO;
import com.dlc.shop.service.SmsLogService;
import com.dlc.shop.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 用户信息
 *
 * @author LGH
 */
@RestController
@RequestMapping("/user")
@Tag(name = "用户注册相关接口")
@AllArgsConstructor
public class UserRegisterController {

    private final UserService userService;


    private final SmsLogService smsLogService;

    private final AppConnectService appConnectService;

    private final TokenStore tokenStore;

    private final PasswordEncoder passwordEncoder;

    private final PasswordManager passwordManager;

    private final LiveRoomService liveRoomService;

    public static final String CHECK_REGISTER_SMS_FLAG = "checkRegisterSmsFlag";

    public static final String CHECK_UPDATE_PWD_SMS_FLAG = "updatePwdSmsFlag";


    /**
     * 只有在pc上使用，所以跟绑定微信openid没啥关系
     */
    @Operation(summary = "注册")
    @PostMapping("/register")
    public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) {

        // 目前注册都是发验证码去注册的，看看有没有校验验证码成功的标识
        userService.validate(userRegisterParam, CHECK_REGISTER_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
        // 正在进行申请注册
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userRegisterParam.getMobile())) > 0) {
            // 该手机号已注册，无法重新注册
            throw new YamiShopBindException("yami.user.phone.exist");
        }

        // 注册成功
        User user = appConnectService.registerAndBindUser(userRegisterParam.getMobile(), userRegisterParam.getPassword(), null);
        if (user.getStatus() == 0) {
            throw new YamiShopBindException("yami.user.disabled");
        }
        // 2. 登录
        return ServerResponseEntity.success(tokenStore.storeAndGetVo(new UidInfoBO(SysTypeEnum.ORDINARY, user.getUserId())));
    }



    @PutMapping("/sendRegisterSms")
    @Operation(summary = "发送注册验证码" , description = "发送注册验证码")
    public ServerResponseEntity<Void> register(@Valid @RequestBody SendSmsParam sendSmsParam) {
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, sendSmsParam.getMobile())) > 0) {
            // 该手机号已注册，无法重新注册
            throw new YamiShopBindException("yami.user.phone.exist");
        }
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SendType.CAPTCHA, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newLinkedHashMap());
        return ServerResponseEntity.success();
    }

    @PutMapping("/checkRegisterSms")
    @Operation(summary = "校验验证码" , description = "校验验证码返回校验成功的标识")
    public ServerResponseEntity<String> register(@Valid @RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        // 每个ip每分钟只能发十个注册的验证码，免得接口被利用
        if (!smsLogService.checkValidCode(checkRegisterSmsParam.getMobile(), checkRegisterSmsParam.getValidCode(), SendType.CAPTCHA)){
            // 验证码有误或已过期
            throw new YamiShopBindException("yami.user.code.error");
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_REGISTER_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ServerResponseEntity.success(checkRegisterSmsFlag);
    }

    @PutMapping("/sendBindSms")
    @Operation(summary = "发送绑定验证码" , description = "发送绑定验证码")
    public ServerResponseEntity<Void> bindSms(@Valid @RequestBody SendSmsParam sendSmsParam) {
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SendType.CAPTCHA, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newLinkedHashMap());
        return ServerResponseEntity.success();
    }


    @PutMapping("/checkUpdatePwdSms")
    @Operation(summary = "修改密码校验验证码" , description = "校验验证码返回校验成功的标识")
    public ServerResponseEntity<String> checkUpdatePwdSms(@RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        boolean isCheckPass = false;
        if (Objects.nonNull(checkRegisterSmsParam) && Objects.nonNull(checkRegisterSmsParam.getMobile())) {
            Matcher m = Pattern.compile(PrincipalUtil.MOBILE_REGEXP).matcher(checkRegisterSmsParam.getMobile());
            isCheckPass = m.matches();
        }
        if (!isCheckPass) {
            throw new YamiShopBindException("yami.user.err.phone");
        }

        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, checkRegisterSmsParam.getMobile()));
        if (user == null) {
            // 此用户不存在，请先注册
            throw new YamiShopBindException("yami.user.account.no.exist");
        }
        if (!smsLogService.checkValidCode(user.getUserMobile(), checkRegisterSmsParam.getValidCode(), SendType.CAPTCHA)) {
            // 验证码有误或已过期
            throw new YamiShopBindException("yami.user.code.error");
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_UPDATE_PWD_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ServerResponseEntity.success(checkRegisterSmsFlag);
    }

    @PutMapping("/updatePwd")
    @Operation(summary = "修改密码" , description = "修改密码")
    public ServerResponseEntity<Void> updatePwd(@Valid @RequestBody UserPwdUpdateParam userPwdUpdateParam, HttpServletRequest request) {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userPwdUpdateParam.getMobile()));
        if (user == null) {
            // 无法获取用户信息
            throw new YamiShopBindException("yami.user.no.exist");
        }
        UserRegisterParam registerParam = BeanUtil.map(userPwdUpdateParam, UserRegisterParam.class);
        // 看看有没有校验验证码成功的标识
        userService.validate(registerParam, CHECK_UPDATE_PWD_SMS_FLAG + userPwdUpdateParam.getCheckRegisterSmsFlag());
        String decryptPassword = passwordManager.decryptPassword(userPwdUpdateParam.getPassword());
        if (StrUtil.isBlank(decryptPassword)) {
            // 新密码不能为空
            throw new YamiShopBindException("yami.user.password.no.exist");
        }
        if (StrUtil.equals(passwordEncoder.encode(decryptPassword), user.getLoginPassword())) {
            // 新密码不能与原密码相同!
            throw new YamiShopBindException("yami.user.password.check");
        }

        SysTypeEnum sysType = null;
        String accessToken = request.getHeader("Authorization");
        if (StrUtil.isNotBlank(accessToken)) {
            UidInfoBO uidInfo = AuthUserContext.getUidInfo(tokenStore.getUidByToken(accessToken));
            sysType = uidInfo.getSysType();
        }


        user.setModifyTime(new Date());
        PasswordUtil.check(decryptPassword);
        user.setLoginPassword(passwordEncoder.encode(decryptPassword));
        userService.updateUsrInfo(user,sysType);

        tokenStore.deleteTokenByUidInfo(new UidInfoBO(SysTypeEnum.ORDINARY, user.getUserId()));
        // 将用户踢出设备
        liveRoomService.quitUser(user.getUserId(), false);
        return ServerResponseEntity.success();
    }
}
